#nullable enable

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.Extensions.Logging;
using PHMEE.PHM.Algorithms.Diagnosis;
using Volo.Abp.Domain.Services;

namespace PHMEE.Managers.Diagnosis;

/// <summary>
/// 风机故障诊断
/// </summary>
public class AirBlower2FaultDiagnosisDomainService : DomainService, IAirBlower2FaultDiagnosisDomainService
{
    private readonly AirBlowerAlg2 _airBlowerAlg2;
    private readonly IBearingParametersDomainService _bearingParametersDomainService;
    private readonly ILogger<IAirBlower2FaultDiagnosisDomainService> _logger;

    public AirBlower2FaultDiagnosisDomainService(
        AirBlowerAlg2 airBlowerAlg2,
        IBearingParametersDomainService bearingParametersDomainService,
        ILogger<IAirBlower2FaultDiagnosisDomainService> logger)
    {
        _airBlowerAlg2 = airBlowerAlg2;
        _bearingParametersDomainService = bearingParametersDomainService;
        _logger = logger;
    }

    /// <summary>
    /// 风机故障诊断
    /// </summary>
    /// <param name="pointPosition"></param>
    /// <param name="sampleRate"></param>
    /// <param name="unitWithEquips"></param>
    /// <param name="data"></param>
    /// <exception cref="ArgumentNullException"></exception>
    /// <returns></returns>
    public async Task<string[]> FaultDiagnosisAsync(PointPosition pointPosition, float sampleRate,
        UnitWithEquipsDto unitWithEquips,
        float[] data)
    {
        // 验证并提取设备信息
        var (asynchronousElectricMotor, centrifugalFan) = ValidateAndExtractUnitEquipments(unitWithEquips.UnitEquips);
        
        // 如果是直驱式风机，则调用方法 2，否则记录警告日志
        if (centrifugalFan.SupportFlexibilityMode is not SupportFlexibilityMode.DirectDrive)
        {
            _logger.LogWarning("风机不是直驱式风机，但却调用了风机故障诊断 2 方法，需要注意！");
        }
        return await AirBlower2FaultDiagnosisAsync(pointPosition, data, sampleRate,
            asynchronousElectricMotor, centrifugalFan, unitWithEquips.Unit);
    }

    /// <summary>
    /// 风机故障诊断 2（用于风机类型是直驱式）
    /// </summary>
    /// <param name="pointPosition"></param>
    /// <param name="data"></param>
    /// <param name="sampleRate"></param>
    /// <param name="asynchronousElectricMotor"></param>
    /// <param name="centrifugalFan"></param>
    /// <param name="unit"></param>
    /// <returns></returns>
    /// <exception cref="InvalidOperationException"></exception>
    private async Task<string[]> AirBlower2FaultDiagnosisAsync(PointPosition pointPosition, float[] data,
        float sampleRate,
        AsynElectricMotor asynchronousElectricMotor, CentrifugalFan centrifugalFan, Unit unit)
    {
        // 设备参数和阈值初始化
        var equipmentParameters = new AirBlower2EquipmentParameters();
        var thresholds = new AirBlower2Thresholds();

        // 提取异步电动机参数
        ExtractAirBlower2AsynchronousElectricMotorParameters(asynchronousElectricMotor, equipmentParameters);

        // 提取鼓风机参数
        ExtractAirBlower2CentrifugalPumpParameters(centrifugalFan, equipmentParameters);

        // 提取轴承信息
        await ExtractAirBlower2BearingParametersAsync(asynchronousElectricMotor, equipmentParameters);

        // 提取阈值
        ExtractAirBlower2Thresholds(unit, thresholds);

        // 调用风机故障诊断 2 算法
        var response = await _airBlowerAlg2.AirBlower2Async(pointPosition, data, sampleRate,
            equipmentParameters, thresholds);

        return response.FaultCodes.ToArray();
    }

    private static (AsynElectricMotor, CentrifugalFan) ValidateAndExtractUnitEquipments(List<Equipment> unitEquips)
    {
        if (unitEquips.Count == 0)
        {
            throw new InvalidOperationException(nameof(Equipment));
        }

        if ((unitEquips.FirstOrDefault(e => e.Type == EquipmentEnum.AsynElectricMotor)
             ?? throw new InvalidOperationException(nameof(EquipmentEnum.AsynElectricMotor)))
            is not AsynElectricMotor asynchronousElectricMotorEquip)
        {
            throw new InvalidOperationException(nameof(AsynElectricMotor));
        }

        asynchronousElectricMotorEquip.DeserializeProperties();

        if ((unitEquips.FirstOrDefault(e => e.Type == EquipmentEnum.CentrifugalFan)
             ?? throw new InvalidOperationException(nameof(EquipmentEnum.CentrifugalFan)))
            is not CentrifugalFan centrifugalFanEquip)
        {
            throw new InvalidOperationException(nameof(CentrifugalFan));
        }

        centrifugalFanEquip.DeserializeProperties();

        return (asynchronousElectricMotorEquip, centrifugalFanEquip);
    }
    
    private static void ExtractAirBlower2AsynchronousElectricMotorParameters(
        AsynElectricMotor asynchronousElectricMotor,
        AirBlower2EquipmentParameters equipmentParameters)
    {
        equipmentParameters.Rpm = (float)asynchronousElectricMotor.MotorSpeed;
        equipmentParameters.Lf = (float)asynchronousElectricMotor.Frequency;
        equipmentParameters.Rbpf = (float)asynchronousElectricMotor.RotorBarsNumber;
        equipmentParameters.Power = (float)asynchronousElectricMotor.Power;
    }

    private static void ExtractAirBlower2CentrifugalPumpParameters(CentrifugalFan centrifugalFan,
        AirBlower2EquipmentParameters equipmentParameters)
    {
        equipmentParameters.Bp = centrifugalFan.BladeNumber;
    }

    private async Task ExtractAirBlower2BearingParametersAsync(AsynElectricMotor asynchronousElectricMotor,
        AirBlower2EquipmentParameters equipmentParameters)
    {
        equipmentParameters.BearMotorDrive.AddRange(await _bearingParametersDomainService.GetBearingParametersAsync(asynchronousElectricMotor.DriveEndBearFactoryFirst, asynchronousElectricMotor.DriveEndBearModelFirst));
        equipmentParameters.BearMotorFree.AddRange(await _bearingParametersDomainService.GetBearingParametersAsync(asynchronousElectricMotor.NonDriveEndBearFactory, asynchronousElectricMotor.NonDriveEndBearModel));
    }

    /// <summary>
    /// 从 Unit 提取 AirBlower2 阈值
    /// </summary>
    /// <param name="unit"></param>
    /// <param name="thresholds"></param>
    private static void ExtractAirBlower2Thresholds(Unit unit, AirBlower2Thresholds thresholds)
    {
        if (unit is CombustionAirBlowerUnit combustionAirBlowerUnit)
        {
            ExtractAirBlower2ThresholdsForCombustionAirBlower(combustionAirBlowerUnit, thresholds);
        }
        else
        {
            throw new InvalidOperationException(nameof(CombustionAirBlowerUnit));
        }
    }
    
    /// <summary>
    /// AirBlower2 燃烧鼓风机阈值提取
    /// </summary>
    /// <param name="unit"></param>
    /// <param name="thresholds"></param>
    private static void ExtractAirBlower2ThresholdsForCombustionAirBlower(CombustionAirBlowerUnit unit, AirBlower2Thresholds thresholds)
    {
        unit.DeserializeProperties();

        thresholds.Acc = (float)unit.Acc;
        thresholds.MRms.AddRange(new[] { (float)unit.MrmsA, (float)unit.MrmsB, (float)unit.MrmsC });
        thresholds.Value1X.AddRange(new[] { (float)unit.Value1XA, (float)unit.Value1XB });
        thresholds.Bear.AddRange(new[]
        {
            (float)unit.BearA,
            (float)unit.BearB,
            (float)unit.BearC,
            (float)unit.BearD,
            (float)unit.BearE1,
            (float)unit.BearE2,
            (float)unit.BearE3,
            (float)unit.BearE4,
            (float)unit.BearE5
        });
        thresholds.ArmatureFault.AddRange(new[] { (float)unit.ArmatureFaultA, (float)unit.ArmatureFaultB });
        thresholds.ImbalanceFault = (float)unit.ImbalanceFault;
        thresholds.ResonanceFault = (float)unit.ResonanceFault;
        thresholds.StructureLoose = (float)unit.StructureLoose;
        thresholds.ImpellerFault = (float)unit.ImpellerFault;
    }
}